<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="qrBQa" id="qrBQa"><span data-lake-id="u700c70c4" id="u700c70c4">典型回答</span></h1>
  <p data-lake-id="u1831dade" id="u1831dade"><br></p>
  <p data-lake-id="u7584f214" id="u7584f214"><span data-lake-id="u2052503c" id="u2052503c">数据库中数据量过多，表太大的时候，不仅可以做分库分表，还可以做表分区，分区和分表类似，都是按照一定的规则将一张大表进行分解。</span></p>
  <p data-lake-id="u417ea015" id="u417ea015"><span data-lake-id="udff9b06e" id="udff9b06e">​</span><br></p>
  <p data-lake-id="u3fc1748a" id="u3fc1748a"><span data-lake-id="u820068dd" id="u820068dd">听上去好像也差不多，不就是将表拆分吗？那具体有什么差别呢？</span></p>
  <p data-lake-id="u7ab34f38" id="u7ab34f38"><span data-lake-id="ua5e0d0a6" id="ua5e0d0a6">​</span><br></p>
  <p data-lake-id="uf9e0466d" id="uf9e0466d"><span data-lake-id="u4fc150a2" id="u4fc150a2">主要是分区和分表后数据的数据存储方式有变化。</span></p>
  <p data-lake-id="u710d34b6" id="u710d34b6"><span data-lake-id="uf76c79d9" id="uf76c79d9">​</span><br></p>
  <p data-lake-id="ud0f92bcf" id="ud0f92bcf"><strong><span data-lake-id="u2436cf25" id="u2436cf25">在Innodb中（8.0之前），表存储主要依赖两个文件，分别是.frm文件和.ibd文件。.frm文件用于存储表结构定义信息，而.ibd文件则用于存储表数据。</span></strong></p>
  <p data-lake-id="ua3c34f58" id="ua3c34f58"><br></p>
  <p data-lake-id="u68745364" id="u68745364"><span data-lake-id="uaba70419" id="uaba70419">假如我们有一张users表，想要对他进行分区和分表，区别如下：</span></p>
  <p data-lake-id="u2ba3fc3d" id="u2ba3fc3d"><br></p>
  <p data-lake-id="u77e25535" id="u77e25535"><span data-lake-id="u75858d73" id="u75858d73">MySQL InnoDB存储引擎在分区表时，会将每一个分区分别存放在一个单独的 .ibd 文件中，所有的 .ibd 文件组合构成表的物理结构，即 Table Space。</span></p>
  <p data-lake-id="u22e9a560" id="u22e9a560"><span data-lake-id="uc7933322" id="uc7933322">​</span><br></p>
  <p data-lake-id="ua140112c" id="ua140112c"><span data-lake-id="ud64b52f3" id="ud64b52f3">对于上面分区的 users表，存储时会在 MySQL 的 data 目录下创建一个用户名+表名+分区名.ibd 的文件（如：users_p1.ibd），用来存储 users 表中第一个分区的数据，同样会有 users_p2.ibd 和 users_p3.ibd 来存储第二和第三个分区的数据：</span></p>
  <p data-lake-id="ubeb3b581" id="ubeb3b581"><span data-lake-id="u99549c4c" id="u99549c4c">​</span><br></p>
  <pre lang="java"><code>
users_p1.ibd
users_p2.ibd
users_p3.ibd
users_p4.ibd
users.frm
</code></pre>
  <p data-lake-id="udc4a260e" id="udc4a260e"><span data-lake-id="uc3df525b" id="uc3df525b">​</span><br></p>
  <p data-lake-id="u3efa2345" id="u3efa2345"><span data-lake-id="uabb6c4ea" id="uabb6c4ea">MySQL InnoDB存储引擎在分表时，会将每一个分表分别存放在一个单独的 .frm 文件中，所有的 .frm 文件组合构成表的逻辑结构，即 Table Definition。</span></p>
  <p data-lake-id="u0827bdbe" id="u0827bdbe"><span data-lake-id="u7e5a9c1c" id="u7e5a9c1c">​</span><br></p>
  <p data-lake-id="ud13d6337" id="ud13d6337"><span data-lake-id="u935fc077" id="u935fc077">对于上面分表的users表，存储时会在 MySQL 的data目录下创建后缀名为“users_1.frm”的表格文件，存储 users 表中第一个分表的数据，同样会有 users_2.frm 和 users_3.frm 来存储第二和第三个分表的数据：</span></p>
  <p data-lake-id="u9d9aa81c" id="u9d9aa81c"><span data-lake-id="ud929f964" id="ud929f964">​</span><br></p>
  <pre lang="java"><code>
users_1.ibd
users_1.frm
users_2.ibd
users_2.frm
users_3.ibd
users_3.frm
users_4.ibd
users_4.frm
</code></pre>
  <p data-lake-id="ua667162e" id="ua667162e"><span data-lake-id="ubac7bfa0" id="ubac7bfa0">​</span><br></p>
  <p data-lake-id="u453560be" id="u453560be"><strong><span data-lake-id="ud0b7e73d" id="ud0b7e73d">在做了分区后，表面是还是只有一张表，只不过数据保存在不同的位置上了（</span></strong><strong><u><span data-lake-id="u4a9bf32f" id="u4a9bf32f">同一个.frm文件</span></u></strong><strong><span data-lake-id="u1698ed06" id="u1698ed06">），在做数据读取的时候操作的表名还是users表，数据库会自己去组织各个分区的数据。</span></strong></p>
  <p data-lake-id="u9cb24aea" id="u9cb24aea"><strong><span data-lake-id="u8b48dad8" id="u8b48dad8">​</span></strong><br></p>
  <p data-lake-id="ue39ac3e1" id="ue39ac3e1"><strong><span data-lake-id="ub4538597" id="ub4538597">而在做了分表之后，不管是表面上，还是实际上，都已经是不同的表了（</span></strong><strong><u><span data-lake-id="u8ef0d006" id="u8ef0d006">多个.frm文件</span></u></strong><strong><span data-lake-id="u2995097b" id="u2995097b">），数据库操作的时候，需要去指定具体的表名。</span></strong></p>
  <p data-lake-id="ua50cbdc2" id="ua50cbdc2"><span data-lake-id="u44d096d2" id="u44d096d2">​</span><br></p>
  <p data-lake-id="u61ffd6d9" id="u61ffd6d9"><strong><span data-lake-id="ubb801c4f" id="ubb801c4f">一般来说，数据量变大时，我们应该先考虑分区，分区搞不定再考虑分表。</span></strong></p>
  <p data-lake-id="uaaf57807" id="uaaf57807"><strong><span data-lake-id="u2fa425bb" id="u2fa425bb">​</span></strong><br></p>
  <p data-lake-id="ue6711f80" id="ue6711f80"><span data-lake-id="u7e9cce6e" id="u7e9cce6e">因为分表可以在分区的基础上，进一步减少查询时的系统开销。因为分表后，单表数据量小，页缓存率更高，I/O读写性能更优，另外分表也能降低了锁带来的阻塞，也可以提高事务处理效率。还有就是小的表可以提升备份和恢复的速度、并且具有更好的横向扩展性。</span></p>
  <p data-lake-id="u410361ad" id="u410361ad"><span data-lake-id="u88492e5c" id="u88492e5c" class="lake-fontsize-12" style="color: rgb(55, 65, 81); background-color: rgb(247, 247, 248)">​</span><br></p>
  <h1 data-lake-id="hcBPT" id="hcBPT"><span data-lake-id="u57eda6dc" id="u57eda6dc">扩展知识</span></h1>
  <p data-lake-id="uc73185d9" id="uc73185d9"><br></p>
  <h2 data-lake-id="rZHYL" id="rZHYL"><strong><span data-lake-id="u6b12be82" id="u6b12be82" style="color: rgb(0, 0, 0)">分区的方式</span></strong></h2>
  <p data-lake-id="ue5d9277d" id="ue5d9277d"><span data-lake-id="uc71d2939" id="uc71d2939">表分区的方式有水平分区、垂直分区：</span></p>
  <ol list="u8cda2c51">
   <li fid="u7273d971" data-lake-id="u6a1bf8bc" id="u6a1bf8bc"><span data-lake-id="uf6173991" id="uf6173991">水平分区：将表根据行进行划分，即把一个表的数据划分成多个表的数据，每个表形成一个分区；这些细分出来的部分存放在多个不同的分区表中（比如按年份等）。每块数据都存放在不同的表中，可以显著提高操作的效率。</span></li>
   <li fid="u7273d971" data-lake-id="u6c736908" id="u6c736908"><span data-lake-id="u35f8a8ad" id="u35f8a8ad">垂直分区：将表根据表字段进行划分，将表中的列（或字段）分割成多个数据表，用于存储不同的业务场景内的数据。使分区后的数据表垂直分离，可以有效减少数据库查询中非必要的访问。</span></li>
  </ol>
  <p data-lake-id="ub2177966" id="ub2177966"><span data-lake-id="ubbfc6219" id="ubbfc6219">​</span><br></p>
  <p data-lake-id="uc2221ac3" id="uc2221ac3"><strong><span data-lake-id="ue98b67b0" id="ue98b67b0">MySQL 数据库支持的分区类型为水平分区。</span></strong></p>
  <p data-lake-id="u5fa93477" id="u5fa93477"><strong><span data-lake-id="u89f1ae24" id="u89f1ae24" class="lake-fontsize-11" style="color: rgb(51, 51, 51)">​</span></strong><br></p>
  <p data-lake-id="u771630f3" id="u771630f3"><strong><span data-lake-id="u61cafe7b" id="u61cafe7b" class="lake-fontsize-11" style="color: rgb(51, 51, 51)">​</span></strong><br></p>
  <p data-lake-id="ud30420f4" id="ud30420f4"><span data-lake-id="ud4ed91de" id="ud4ed91de">常见的表分区实践中，可以按照以下一些原则进行分区：</span></p>
  <p data-lake-id="ue48a81f7" id="ue48a81f7"><strong><span data-lake-id="u0a99969b" id="u0a99969b" class="lake-fontsize-11" style="color: rgb(51, 51, 51)">​</span></strong><br></p>
  <ol list="ub4863651">
   <li fid="u8ed7d234" data-lake-id="u31b9e5ce" id="u31b9e5ce"><span data-lake-id="u8ee51f13" id="u8ee51f13">按照系统负载，将数据分到不同的区域中；</span></li>
   <li fid="u8ed7d234" data-lake-id="u0456de68" id="u0456de68"><span data-lake-id="uece75681" id="uece75681">按照应用程序查询模式，将数据库分为不同的分区；</span></li>
   <li fid="u8ed7d234" data-lake-id="ue50477f9" id="ue50477f9"><span data-lake-id="u1fe1c14e" id="u1fe1c14e">按照月份或者年份分区；</span></li>
   <li fid="u8ed7d234" data-lake-id="uf06f4ed9" id="uf06f4ed9"><span data-lake-id="uef01f58d" id="uef01f58d">通过实践哈希法可以将记录放置到不同的分区中；</span></li>
   <li fid="u8ed7d234" data-lake-id="u79ac24e4" id="u79ac24e4"><span data-lake-id="ub82a1759" id="ub82a1759">基于范围查询，使用分段来将记录放置到不同的分区中，以便提高查询效率。</span></li>
  </ol>
  <p data-lake-id="uaa4a4640" id="uaa4a4640"><span data-lake-id="u55f4fd0d" id="u55f4fd0d">​</span><br></p>
  <p data-lake-id="u3e2c1191" id="u3e2c1191"><span data-lake-id="u250356d0" id="u250356d0">​</span><br></p>
  <p data-lake-id="uc1bb64be" id="uc1bb64be"><span data-lake-id="u711dbfe4" id="u711dbfe4">MySQL水平分区的</span><strong><span data-lake-id="u87da4765" id="u87da4765">创建方法</span></strong><span data-lake-id="u2f068d9c" id="u2f068d9c">：</span></p>
  <p data-lake-id="u0cf0be10" id="u0cf0be10"><span data-lake-id="ua7ee750f" id="ua7ee750f">​</span><br></p>
  <pre lang="java"><code>
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    order_date DATE,
    customer_id INT,
    total_amount DECIMAL(10, 2)
) PARTITION BY RANGE (YEAR(order_date)) (
    PARTITION p0 VALUES LESS THAN (2020),
    PARTITION p1 VALUES LESS THAN (2021),
    PARTITION p2 VALUES LESS THAN (2022),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);
</code></pre>
  <p data-lake-id="ubd57b982" id="ubd57b982"><br></p>
 </body>
</html>